//Copyright (c) 2014, Jesse de Waard
//All rights reserved.

//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions are met:
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//    * Neither the name of the <organization> nor the
//      names of its contributors may be used to endorse or promote products
//      derived from this software without specific prior written permission.

//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//DISCLAIMED. IN NO EVENT SHALL JESSE DE WAARD BE LIABLE FOR ANY
//DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <assert.h>
#include <screen/screen.h>
#include <bps/navigator.h>
#include <bps/screen.h>
#include <bps/bps.h>
#include <bps/event.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>

#include <EGL/egl.h>
#include <GLES/gl.h>

#include "bbutil.h"
#include "objects.h"

int translated = 0;
static GLfloat vertices[8];
static GLfloat colors[16];
static GLfloat texcoords[8];
static GLuint textureBackground;
static GLuint texturePuck;
static GLuint textureStick;

char stringBuff[20];

static font_t* font;

static screen_context_t screen_cxt;

static EGLint surface_width, surface_height;
static GLfloat width,height;

static GLfloat xMax, xMin, yMax, yMin;

player player1 = {0.15f,0.15f,0.5f,0.0f,0.0f,0.0f,0.0f,1,0,0,0};
player player2 = {0.15f,0.15f,-0.5f,0.0f,0.0f,0.0f,0.0f,2,0,0,1};
puck puck1 	   = {0.06f,0.06f,0.0f,0.01f,0.01f,1.0f,0.0f};



void updatePuckPositions(GLfloat xpos, GLfloat ypos, GLfloat dirx, GLfloat diry, GLfloat speed){
	puck1.x = xpos;
	puck1.y = xpos;
	puck1.dirx = dirx;
	puck1.diry = diry;
	puck1.speed = speed;
}

void checkBoundary(GLfloat xpos, GLfloat ypos, player *playerx){
	// Keep stick in playfield
	if(playerx->player == 1){
		xpos = max(xpos,    0 + playerx->width/2);
		xpos = min(xpos, xMax - playerx->width/2);
		playerx->x = xpos;

		ypos = max(ypos, yMin + playerx->height/2);
		ypos = min(ypos, yMax - playerx->height/2);
		playerx->y = ypos;
	}

	if(playerx->player == 2){
		xpos = max(xpos, xMin + playerx->width/2);
		xpos = min(xpos, 0 - playerx->width/2);
		playerx->x = xpos;

		ypos = max(ypos, yMin + playerx->height/2);
		ypos = min(ypos, yMax - playerx->height/2);
		playerx->y = ypos;
	}
}

//Update de joystick positie doormiddel van de touch coordinaten
void updateJoystick(int x, int y,int id){

	GLfloat xpos,ypos;
	xpos = (width/(GLfloat)surface_width)*((GLfloat)x-(surface_width/2));
	ypos = (height/(GLfloat)surface_height)*((GLfloat)y-(surface_height/2))*-1;

	if(id == player1.touchId){
		checkBoundary(xpos,ypos,&player1);
	}
	else if(id == player2.touchId){
		checkBoundary(xpos,ypos,&player2);
	}
}

//De handeler voor de screen events(touch etc.)
void handleScreenEvent(bps_event_t *event) {
    screen_event_t screen_event = screen_event_get_event(event);
    int pair[2];
    int id;
    int screen_val;

    screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE,
            &screen_val);
    screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION,
                pair);
    screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID,
                    &id);

    switch (screen_val) {
    case SCREEN_EVENT_MTOUCH_TOUCH:
    	break;
    case SCREEN_EVENT_MTOUCH_MOVE:
    	updateJoystick(pair[0],pair[1],id);
    	break;
    case SCREEN_EVENT_MTOUCH_RELEASE:
        break;
    }
}

int initialize() {

    vertices[0] = -1.0f;
    vertices[1] = -1.0f;

    vertices[2] = 1.0f;
    vertices[3] = -1.0f;

    vertices[4] = -1.0f;
    vertices[5] = 1.0f;

    vertices[6] = 1.0f;
    vertices[7] = 1.0f;


    colors[0] = 1.0f;
    colors[1] = 1.0f;
    colors[2] = 1.0f;
    colors[3] = 1.0f;

    colors[4] = 1.0f;
    colors[5] = 1.0f;
    colors[6] = 1.0f;
    colors[7] = 1.0f;

    colors[8] = 1.0f;
    colors[9] = 1.0f;
    colors[10] = 1.0f;
    colors[11] = 1.0f;

    colors[12] = 1.0f;
    colors[13] = 1.0f;
    colors[14] = 1.0f;
    colors[15] = 1.0f;


    texcoords[0] = 0.0f;
    texcoords[1] = 0.0f;

    texcoords[2] = 1.0f;
    texcoords[3] = 0.0f;

    texcoords[4] = 0.0f;
    texcoords[5] = 1.0f;

    texcoords[6] = 1.0f;
    texcoords[7] = 1.0f;


    eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width);
    eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height);

    EGLint err = eglGetError();
    if (err != 0x3000) {
        fprintf(stderr, "Unable to query EGL surface dimensions\n");
        return EXIT_FAILURE;
    }

    int dpi = bbutil_calculate_dpi(screen_cxt);

    if (dpi == EXIT_FAILURE) {
        fprintf(stderr, "Unable to calculate dpi\n");
        return EXIT_FAILURE;
    }

    font = bbutil_load_font(
                "/usr/fonts/font_repository/adobe/MyriadPro-Bold.otf", 15, dpi);
    if (!font) {
        return EXIT_FAILURE;
    }

    //Hoogte en breedte van het scherm volgens GLfloats
    width =  (float) (surface_width) / (float) (surface_height);
    height = 1.0f;

    //Maximum en mimumums van het speler veld
    xMax = width/2;
    xMin = -(width/2);
    yMax = height/2;
    yMin = -(height/2);

    //Initialisatie van van alles
    glShadeModel(GL_SMOOTH);

    glClearColor(0.5f, 0.5f, 0.9f, 1.0f);

    glViewport(0, 0, surface_width, surface_height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    //Schaal assenstelsel in 16:9
    glOrthof(0.0f,width, 0.0f, height, -1.0f, 1.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    //Translate naar midden punt = 0,0
    glTranslatef(width / 2, height / 2, 0.0f);

    //Laad de plaatjes in als textures
    static int texwidth, texheight;
    float tex_x, tex_y;

    bbutil_load_texture("app/native/images/Background.png", &texwidth, &texheight, &tex_x, &tex_y, &textureBackground);
    bbutil_load_texture("app/native/images/puck.png", &texwidth, &texheight, &tex_x, &tex_y, &texturePuck);
    bbutil_load_texture("app/native/images/joystick.png", &texwidth, &texheight, &tex_x, &tex_y, &textureStick);
    return EXIT_SUCCESS;
}

void render() {
    //Render het scherm
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_TEXTURE_2D);
    //glBindTexture(GL_TEXTURE_2D, texturePuck);

    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(2, GL_FLOAT, 0, vertices);

    glEnableClientState(GL_COLOR_ARRAY);
    glColorPointer(4, GL_FLOAT, 0, colors);

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2,GL_FLOAT,0,texcoords);

    glPushMatrix();
    //glVertexPointer(2, GL_FLOAT, 0, verticesBackground);
    glBindTexture(GL_TEXTURE_2D, textureBackground);
    glScalef(width/2,width/2,0.0f);
    //glTranslatef(0.0f,0.4f,0.0f);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glPopMatrix();


    int i;
    for(i=0;i<3;i++){
    	glPushMatrix();
    	switch(i)
    	{
    		//Puck
    		case 0:
    			glBindTexture(GL_TEXTURE_2D, texturePuck);
    			glTranslatef(puck1.x + (puck1.dirx * puck1.speed),
    					puck1.y + (puck1.diry * puck1.speed),0.0f);
    			glScalef(puck1.width,puck1.height,0.0f);
    			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    			break;

    		//Player 1
    		case 1:
    			glBindTexture(GL_TEXTURE_2D, textureStick);
    			glTranslatef(player1.x,player1.y,0.0f);
    			glScalef(player1.width,player1.height,0.0f);
    			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    			break;

    		//Player 2
    		case 2:
    			glBindTexture(GL_TEXTURE_2D, textureStick);
    			glTranslatef(player2.x,player2.y,0.0f);
    			glScalef(player2.width,player2.height,0.0f);
    			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    			break;

    		default :
    			break;
    	}
    	glPopMatrix();

    }

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);

    glPushMatrix();
    sprintf(stringBuff,"%d  %d",player2.score,player1.score);
    glScalef(1.0f / 600.0f, 1.0f / 600.0f, 1.0f);
    bbutil_render_text(font, stringBuff, -500.0f, 255.0f, 0.0f, 0.0f, 0.0f, 1.0f);
    glPopMatrix();

    //Use utility code to update the screen
    bbutil_swap();
}

int main(int argc, char *argv[]) {
    int rc;
    int exit_application = 0;


    //Create a screen context that will be used to create an EGL surface to to receive libscreen events
    screen_create_context(&screen_cxt, 0);

    //Initialize BPS library
    bps_initialize();

    //Use utility code to initialize EGL for rendering with GL ES 1.1
    if (EXIT_SUCCESS != bbutil_init_egl(screen_cxt)) {
        fprintf(stderr, "bbutil_init_egl failed\n");
        bbutil_terminate();
        screen_destroy_context(screen_cxt);
        return 0;
    }

    //Initialize application logic
    if (EXIT_SUCCESS != initialize()) {
        fprintf(stderr, "initialize failed\n");
        bbutil_terminate();
        screen_destroy_context(screen_cxt);
        return 0;
    }

    //Signal BPS library that navigator and screen events will be requested
    if (BPS_SUCCESS != screen_request_events(screen_cxt)) {
        fprintf(stderr, "screen_request_events failed\n");
        bbutil_terminate();
        screen_destroy_context(screen_cxt);
        return 0;
    }

    if (BPS_SUCCESS != navigator_request_events(0)) {
        fprintf(stderr, "navigator_request_events failed\n");
        bbutil_terminate();
        screen_destroy_context(screen_cxt);
        return 0;
    }

    //Signal BPS library that navigator orientation is not to be locked
    if (BPS_SUCCESS != navigator_rotation_lock(false)) {
        fprintf(stderr, "navigator_rotation_lock failed\n");
        bbutil_terminate();
        screen_destroy_context(screen_cxt);
        return 0;
    }
    while (!exit_application) {
        //Request and process all available BPS events
        bps_event_t *event = NULL;

        for(;;) {
            rc = bps_get_event(&event, 0);
            assert(rc == BPS_SUCCESS);

            if (event) {
                int domain = bps_event_get_domain(event);

                if (domain == screen_get_domain()) {
                    handleScreenEvent(event);
                } else if ((domain == navigator_get_domain())
                        && (NAVIGATOR_EXIT == bps_event_get_code(event))) {
                    exit_application = 1;
                }
            } else {
                break;
            }
        }
        render();
    }

    //Stop requesting events from libscreen
    screen_stop_events(screen_cxt);

    //Shut down BPS library for this process
    bps_shutdown();

    //Use utility code to terminate EGL setup
    bbutil_terminate();

    //Destroy libscreen context
    screen_destroy_context(screen_cxt);
    return 0;
}
